﻿//-----------------------------------------------------------------------
// <copyright>
// Copyright (C) Sergey Solyanik for The Black Square Project.
// Adopted from Malevich code (C) Sergey Solyanik and Eldar Musaev.
//
// This file is subject to the terms and conditions of the Microsoft Public License (MS-PL).
// See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL for more details.
// </copyright>
//----------------------------------------------------------------------- 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Notifier
{
    /// <summary>
    /// Implements support for notifier email customizations.
    /// 
    /// To customize email that notifier sends, create the following text files, and drop them in the same directory
    /// where Notifier.exe lives: Request.txt, Invite.txt, Iteration.txt, and Response.txt.
    /// 
    /// The files should contain the text which is sent, respectively, when a reviewer is asked to join code review,
    /// when the code invitation is sent, when a reviewer makes comments, and when reviewee responds to the comments.
    /// 
    /// The files should contain the following macros which are replaced whith real values (macro names are
    /// case-sensitive):
    /// Request.txt:
    ///     {Reviewer} - the alias of the reviewer to which email is sent.
    ///     {Webserver} - the server name where BlackSquare web site lives.
    ///     {WebRoot} - the application's path on the site (e.g. BlackSquare)
    ///     {DocumentSetId} - the id of the document set in BlackSquare.
    ///     {Reviewee} - the person requesting code review.
    ///     {Details} - the description of the document set.
    ///     
    ///     The default template:
    ///     
    ///     Dear {Reviewer},
    ///     
    ///     I would like a document review. Please go to http://{Webserver}/{WebRoot}/default.aspx?dsid={DocumentSetId}
    ///     to comment.
    ///     
    ///     If you are super busy and cannot do the review soon, kindly notify me immediately so
    ///     I could plan for contingencies.
    ///     
    ///       --  {Reviewee}
    ///     
    ///     ---------
    ///     
    ///     {Details}
    /// 
    /// Invite.txt:
    ///     {Webserver} - the server name where BlackSquare web site lives.
    ///     {WebRoot} - the application's path on the site (e.g. BlackSquare)
    ///     {DocumentSetId} - the id of the document set in BlackSquare.
    ///     {Reviewee} - the person requesting code review.
    ///     {Details} - the description of the document set.
    ///     
    ///     The default template:
    ///     
    ///     Dear potential reviewer,
    ///     
    ///     I am in need of your professional opinion. Could you do a code review for me?
    ///     
    ///     To accept the review request (thank you! thank you! thank you!), click on this link:
    ///     http://{Webserver}/{WebRoot}/default.aspx?dsid={DocumentSetId}&action=makemereviewer
    ///     
    ///     To learn more about this document, please go to
    ///     http://{Webserver}/{WebRoot}/default.aspx?dsid={DocumentSetId}
    ///     
    ///     You can add yourself as a reviewer there as well.
    ///     
    ///     Thank you very, very much!
    ///     
    ///       --  {Reviewee}
    ///     
    ///     ---------
    ///     
    ///     {Details}
    /// 
    /// Iteration.txt:
    ///     {Reviewee} - the person requesting code review.
    ///     {Verdict} - What is the final verdict (needs work/LGTM/etc). This is a full sentence supplied by the
    ///         notifier. 
    ///     {Webserver} - the server name where BlackSquare web site lives.
    ///     {WebRoot} - the application's path on the site (e.g. BlackSquare)
    ///     {DocumentSetId} - the id of the document set in BlackSquare.
    ///     {Reviewer} - the alias of the reviewer to which email is sent.
    ///     {Details} - the overall comment made by the reviewer
    /// 
    ///     The default template:
    ///     
    ///     Dear {Reviewee},
    ///     
    ///     Thank you for giving me the opportunity to review your code.
    ///     
    ///     {Verdict}
    ///     
    ///     Please see the detailed comments at http://{Webserver}/{WebRoot}/default.aspx?dsid={DocumentSetId}
    ///     
    ///       --  {Reviewer}
    ///     
    ///     ---------
    ///     
    ///     {Details}
    /// 
    /// 
    /// Response.txt:
    ///     {Webserver} - the server name where BlackSquare web site lives.
    ///     {WebRoot} - the application's path on the site (e.g. BlackSquare)
    ///     {DocumentSetId} - the id of the document set in BlackSquare.
    ///     {Reviewee} - the person requesting code review.
    ///     {Details} - the overall comment made by the reviewee
    /// 
    ///     The default template:
    ///     
    ///     Dear reviewers,
    /// 
    ///     Thank you for your comments. Please see my responses at
    ///     http://{Webserver}/{WebRoot}/default.aspx?dsid={DocumentSetId}
    ///     
    ///       -- {Reviewee}
    ///     
    ///     ---------
    ///     
    ///     {Details}
    /// 
    /// Reminder.txt:
    ///     {Webserver} - the server name where BlackSquare web site lives.
    ///     {WebRoot} - the application's path on the site (e.g. BlackSquare)
    ///     {DocumentSetId} - the id of the document set in BlackSquare.
    ///     {Reviewee} - the person requesting code review.
    ///     {Details} - the description of the document set list.
    ///     
    ///     The default template:
    ///     
    ///     Dear {Reviewee},
    ///
    ///     Your document review (http://{Webserver}/{WebRoot}/default.aspx?dsid={DocumentSetId}) is now very, very old!
    ///
    ///     Chances are that the review has already been finalized and you just need to close the it.
    ///
    ///     Otherwise consider reminding your reviewers about it!
    ///
    ///       --  BlackSquare
    ///
    ///     ---------
    ///
    ///     {Details}
    ///
    /// </summary>
    public sealed class MailTemplates
    {
        /// <summary>
        /// Types of email that can be sent.
        /// </summary>
        public enum MailType
        {
            Request = 0,
            Invite,
            Iteration,
            Response,
            Reminder
        }

        /// <summary>
        /// Review request. Sent when reviewer is explicitly assigned. (review 5151 alice)
        /// </summary>
        private const string Request = "Dear {Reviewer},\n\nI would like a document review. " +
            "Please go to http://{Webserver}/{WebRoot}/default.aspx?dsid={DocumentSetId} to comment.\n\n" +
            "If you are super busy and cannot do the review soon, kindly notify me immediately so " +
            "I could plan for contingencies.\n\n  --  {Reviewee}\n\n---------\n\n{Details}";

        /// <summary>
        /// Invitation to join the review. Sent when review is requested with --invite flag. (review 5151 --invite bob)
        /// </summary>
        private const string Invitation = "Dear potential reviewer,\n\nI am in need of your professional opinion. " +
            "Could you do a document review for me?\n\nTo accept the review request " +
            "(thank you! thank you! thank you!), click on this link: " +
            "http://{Webserver}/{WebRoot}/default.aspx?dsid={DocumentSetId}&action=makemereviewer\n\nTo learn more " +
            "about this document, please go to http://{Webserver}/{WebRoot}/default.aspx?dsid={DocumentSetId}" +
            "\n\nYou can add yourself as a reviewer there as well.\n\nThank you very, very much!\n\n" +
            "  --  {Reviewee}\n\n---------\n\n{Details}";

        /// <summary>
        /// The mail that is sent when a reviewer reviews the code.
        /// </summary>
        private const string Iteration = "Dear {Reviewee},\n\nThank you for giving me the opportunity to review " +
            "your document.\n\n{Verdict}\n\nPlease see the detailed comments at\n\n" +
            "http://{Webserver}/{WebRoot}/default.aspx?dsid={DocumentSetId}\n\n  --  {Reviewer}\n\n---------" +
            "\n\n{Details}";

        /// <summary>
        /// The mail that is sent when a reviewee responds to the comments.
        /// </summary>
        private const string Response = "Dear reviewers,\n\nThank you for your comments. Please see my responses at\n" +
            "\nhttp://{Webserver}/{WebRoot}/default.aspx?dsid={DocumentSetId}\n\n  -- {Reviewee}\n\n---------" +
            "\n\n{Details}";

        /// <summary>
        /// The mail that is sent periodically to remind people about old reviews.
        /// </summary>
        private const string Reminder = "Dear {Reviewee},\n\nYour document set " +
            "(http://{Webserver}/{WebRoot}/default.aspx?dsid={DocumentSetId}) is now very, very old!\n\n" +
            "Chances are that the review has already been finalized and you just need to close the it.\n" +
            "Otherwise consider reminding your reviewers about it!\n\n  --  BlackSquare\n\n---------\n\n{Details}";

        /// <summary>
        /// Hashtable that maps the template type to the template text.
        /// </summary>
        private Dictionary<MailType, String> mailTypes = new Dictionary<MailType, String>();

        /// <summary>
        /// Converts the template name to arguments that string formatting understands.
        /// Currently:
        ///     {DocumentSetId} => {0}
        ///     {Reviewer} => {1}
        ///     {Reviewee} => {2}
        ///     {Webserver} => {3}
        ///     {WebRoot} => {4}
        ///     {Verdict} => {5}
        ///     {Details} => {6}
        /// Not every item must be present in the review template.
        /// </summary>
        /// <param name="template"></param>
        /// <returns></returns>
        private string PrepTemplate(string template)
        {
            return template.Replace("{DocumentSetId}", "{0}").Replace("{Reviewer}", "{1}").Replace("{Reviewee}", "{2}")
                .Replace("{Webserver}", "{3}").Replace("{WebRoot}", "{4}").Replace("{Verdict}", "{5}")
                .Replace("{Details}", "{6}");
        }

        /// <summary>
        /// Retrieves the template for the mail.
        /// </summary>
        /// <param name="mailType"> Which mail type we are sending. </param>
        /// <returns> The template. </returns>
        private string GetTemplate(MailType mailType)
        {
            if (mailType != MailType.Invite && mailType != MailType.Iteration && mailType != MailType.Request &&
                mailType != MailType.Response && mailType != MailType.Reminder)
                throw new ArgumentException("mailType");

            if (!mailTypes.ContainsKey(mailType))
            {
                string res = null;
                string path = Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]);
                string fileName = Path.Combine(path, mailType.ToString() + ".txt");
                try
                {
                    if (File.Exists(fileName))
                    {
                        res = File.ReadAllText(fileName);
                        Console.WriteLine("Using template @ " + fileName);
                    }
                }
                catch (IOException e)
                {
                    // Eat the exception.
                    Console.WriteLine(e.ToString());
                }

                if (res == null)
                {
                    switch (mailType)
                    {
                        case MailType.Request:
                            res = Request;
                            break;
                        case MailType.Invite:
                            res = Invitation;
                            break;
                        case MailType.Iteration:
                            res = Iteration;
                            break;
                        case MailType.Response:
                            res = Response;
                            break;
                        case MailType.Reminder:
                            res = Reminder;
                            break;
                    }
                }

                mailTypes[mailType] = PrepTemplate(res);
            }
            return mailTypes[mailType];
        }

        /// <summary>
        /// Given parameters, formats the email. Not all parameters are used in all templates - pass only what you need,
        /// null everything else.
        /// </summary>
        /// <param name="mailType"> Which template to use. </param>
        /// <param name="documentSetId"> DocumentSetId of the review. </param>
        /// <param name="reviewer"> User name for the reviewer. </param>
        /// <param name="reviewee"> User name for the reviewee. </param>
        /// <param name="webserver"> The name of the web server where BlackSquare web site is hosted. </param>
        /// <param name="webRoot">  The application name on the server. </param>
        /// <param name="verdict"> The verdict. </param>
        /// <param name="details"> The details. </param>
        /// <returns> The template. </returns>
        public string CreateMail(MailType mailType, int documentSetId, string reviewer, string reviewee,
            string webserver, string webRoot, string verdict, string details)
        {
            return String.Format(GetTemplate(mailType), documentSetId, reviewer, reviewee, webserver, webRoot, verdict,
                details);
        }
    }
}
